home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_57 / rm.pas < prev    next >
Pascal/Delphi Source File  |  1995-01-01  |  39KB  |  1,208 lines

  1.  
  2. {  Rowan McKenzie's personalised functions for Turbo Pascal 4  28/3/89}
  3.  
  4. Unit rm;
  5.  
  6.   {$v-}
  7.  
  8.   {************************************************************************}
  9.  
  10. Interface
  11.  
  12. Uses crt, graph, mousfunc, printer;
  13.  
  14.  
  15. Const
  16.   dialogstringlength = 100;
  17.   clickboxstringlength = 100;
  18.  
  19. Type
  20.   argtypes       = (_none, _boolean, _char, _integer, _real, _string);
  21.   dialogentryp   = ^dialogentrytype;
  22.   dialogentrytype = Record
  23.                       next           : dialogentryp;
  24.                       title          : String[dialogstringlength];
  25.                       Case argtype   : argtypes Of
  26.                         _none          : ();
  27.                         _boolean : (booleanresult : Boolean);
  28.                         _char : (charresult : Char);
  29.                         _integer : (integerresult : Integer);
  30.                         _real : (realresult     : Real;
  31.                                 decimalp       : Integer);
  32.                         _string : (stringresult   : String[dialogstringlength];
  33.                                   ssize : Byte; nulvalid : Boolean);
  34.                     End;
  35.   titletype      = (_text, _figure);
  36.   polypointp     = ^polypoint;
  37.   polypoint = Record
  38.                 x, y           : Integer;
  39.               End;
  40.   clickboxtypep  = ^clickboxtype;
  41.   clickboxtype = Record
  42.                    next           : clickboxtypep;
  43.                    x, y           : Integer; {box top left corner position}
  44.                    Case ttype     : titletype Of
  45.                      _text : (title : String[clickboxstringlength]);
  46.                      _figure : (numpoints : Word; polypoints : polypointp;
  47.                                 fill           : Boolean);
  48.                  End;
  49.  
  50. Var exitsave   : Pointer;
  51.   showerrormessage : Boolean;
  52.  
  53.  
  54. Procedure heaperrorinit;
  55.  
  56.   { initialised head error pointer to custom procedure}
  57.  
  58. Function log(a : Real)      : Real;
  59.  
  60.   { calculates log base 10 of a}
  61.  
  62. Procedure fixcursor;
  63.  
  64.   { restores correct cursor for Herc card}
  65.  
  66. Procedure readinteger(Var num : Integer);
  67.  
  68. { readlns an integer from kbd. if enter or invalid entry is entered,
  69.   leaves num unchanged}
  70.  
  71. Procedure readlongint(Var num : LongInt);
  72.  
  73. { readlns a long integer from kbd. if enter or invalid entry is entered,
  74.   leaves num unchanged}
  75.  
  76. Procedure readreal(Var num : Real);
  77.  
  78. { readlns a real from kbd. if enter or invalid entry is entered,
  79.   leaves num unchanged}
  80.  
  81. Procedure greadstring(Var s : String; fieldwidth : Integer);
  82.  
  83.   { readlns a string from kbd in graphics mode}
  84.  
  85. Procedure greadinteger(Var num : Integer);
  86.  
  87. { readlns an integer from kbd in graphics mode. if enter or invalid entry is
  88.   entered, leaves num unchanged}
  89.  
  90. Procedure greadlongint(Var num : LongInt);
  91.  
  92. { readlns a long integer from kbd in graphics mode. if enter or invalid entry
  93.   is entered, leaves num unchanged}
  94.  
  95. Procedure greadreal(Var num : Real);
  96.  
  97. { readlns a real from kbd in graphics mode. if enter or invalid entry is
  98.   entered, leaves num unchanged}
  99.  
  100. Procedure swapscreen;
  101.  
  102.   { change virtual graphics pages, saving current page to heap}
  103.  
  104. Procedure leavegraph;
  105.  
  106.   { return to text mode, but save screen on heap}
  107.  
  108. Procedure entergraph(graphmode : Integer);
  109.  
  110.   { return to graphics mode, restoring saved screen from heap}
  111.  
  112. Procedure screendump;
  113.  
  114.   { graphics hardware independant graphics screen dump}
  115.  
  116. Procedure add_dialogentry(Var dp, lastdialogentry,
  117.                           dialogentryhead : dialogentryp);
  118.  
  119.   { appends dialog entry to list}
  120.  
  121. Procedure dialog_box(dialog : dialogentryp; bcolor, color : Integer;
  122.                      continueprompt : Boolean);
  123.  
  124. { draws arguments messages in dialog box, allows editing of fields,
  125.   restores area under box}
  126.  
  127. Procedure dispose_dialog(Var dp : dialogentryp);
  128.  
  129.   { disposes of all entries in dialog list}
  130.  
  131. Procedure beep;
  132.  
  133.   { short beep on console }
  134.  
  135. Procedure selectcolor(color : Word);
  136.  
  137.   { calls setcolor with modified color value depending on available colors}
  138.  
  139. Procedure selectbcolor(color : Word);
  140.  
  141. Procedure selectfillstyle(pattern : Word; color : Word);
  142.  
  143. { calls selectfillstyle with modified color value depending on available
  144.   colors}
  145.  
  146. Procedure selectbfillstyle(pattern : Word; color : Word);
  147.  
  148. { calls selectfillstyle with modified background color value depending on
  149.   available colors}
  150.  
  151. Procedure fill_background(color, fillpattern, arcsize : Word);
  152.  
  153.   { fills background with color and rounds the corners}
  154.  
  155. Procedure panel(x, y : Integer; width, height, color : Word);
  156.  
  157.   { draws solid panel with center top at x,y, width by height}
  158.  
  159. Procedure add_clickboxentry(Var cp, lastclickbox, clickboxhead : clickboxtypep);
  160.  
  161.   { appends clickbox to list}
  162.  
  163. Procedure draw_clicklist(cp : clickboxtypep; x, y, bcolor, color : Integer);
  164.  
  165.   { draws list of click boxes at given offset}
  166.  
  167. Function click_selection(cp : clickboxtypep; x, y : Integer) : Integer;
  168.  
  169.   { tests whether mouse is over a click box and returns its number in the list}
  170.  
  171. Procedure dispose_clickboxlist(Var cp : clickboxtypep);
  172.  
  173.   { disposes of all entries in click box list}
  174.  
  175. Function continue_prompt(x, y, bcolor, color : Integer) : Char;
  176.  
  177.   { displays continue prompt and waits for button or key}
  178.  
  179. Procedure display_message(s : String; bcolor, color : Integer;
  180.                           Var storagep : Pointer; show       : Boolean);
  181.  
  182.   { draws message in box at screen center (or restores screen if show=false)}
  183.  
  184.  
  185.  
  186.   {********************************************************************}
  187.  
  188. Implementation
  189.  
  190. Const
  191.   screens        = 2;
  192.   bigemptystring =
  193.   '                                                                                                                       ';
  194.  
  195. Var scrnbufp   : Array[1..screens] Of Pointer;
  196.                                   {points to graphics screen save areas}
  197.   currentscreen  : Byte;          {virtual graphics screen currently active}
  198.   firstget       : Array[1..screens] Of Boolean;
  199.                                   {indicate first time screen is saved}
  200.   firstput       : Array[1..screens] Of Boolean;
  201.                                   {indicate first time screen is restored}
  202.   i              : Integer;
  203.  
  204.  
  205.  
  206.   Function log(a : Real)      : Real;
  207.  
  208.     { calculates log base 10 of a}
  209.  
  210.   Begin
  211.     log := 0.434294481*ln(a);
  212.   End;
  213.  
  214.  
  215.   Procedure fixcursor;
  216.  
  217.   Begin
  218.     MemW[0:$460] := $0b0c;
  219.   End;                            {fixcursor}
  220.  
  221.  
  222.   {$f+}
  223.   Procedure myexit; {$f-}
  224.  
  225.     { incase graphics mode, restore text screen before error message is given}
  226.  
  227.   Begin
  228.     restorecrtmode;
  229.     ExitProc := exitsave;
  230.     If showerrormessage Then
  231.       WriteLn('Exit due to internal error!');
  232.   End;                            {myexit}
  233.  
  234.  
  235.   {$f+} Function heapfunc(size : Word)   : Integer; {$f-}
  236.  
  237.     { called when heap error occurs}
  238.  
  239.   Begin
  240.     heapfunc := 1;
  241.     restorecrtmode;
  242.     WriteLn;
  243.     WriteLn;
  244.     WriteLn('Insufficient memory - sorry.', ^g);
  245.     WriteLn;
  246.     Halt;
  247.   End;                            {heapfunc}
  248.  
  249.  
  250.   Procedure heaperrorinit;
  251.  
  252.     { initialised head error pointer to custom procedure}
  253.  
  254.   Begin
  255.     HeapError := @heapfunc;
  256.   End;                            {heaperrorinit}
  257.  
  258.  
  259.   Procedure readinteger(Var num : Integer);
  260.  
  261. { readlns an integer from kbd. if enter or invalid entry is entered,
  262.   leaves num unchanged}
  263.  
  264.   Var st         : String;
  265.     code           : Integer;
  266.     number         : LongInt;
  267.  
  268.   Begin
  269.     ReadLn(st);
  270.     If st <> '' Then
  271.     Begin
  272.       Val(st, number, code);
  273.       If (code = 0) And (number >= -MaxInt) And (number <= MaxInt) Then
  274.         num := number;
  275.     End;
  276.   End;                            {readinteger}
  277.  
  278.  
  279.   Procedure readlongint(Var num : LongInt);
  280.  
  281. { readlns a long integer from kbd. if enter or invalid entry is entered,
  282.   leaves num unchanged}
  283.  
  284.   Var st         : String;
  285.     code           : Integer;
  286.     number         : LongInt;
  287.  
  288.   Begin
  289.     ReadLn(st);
  290.     If st <> '' Then
  291.     Begin
  292.       Val(st, number, code);
  293.       If code = 0 Then
  294.         num := number;
  295.     End;
  296.   End;                            {readlongint}
  297.  
  298.  
  299.   Procedure readreal(Var num : Real);
  300.  
  301. { readlns a real from kbd. if enter or invalid entry is entered,
  302.   leaves num unchanged}
  303.  
  304.   Var st         : String;
  305.     code           : Integer;
  306.     number         : Real;
  307.  
  308.   Begin
  309.     ReadLn(st);
  310.     If st <> '' Then
  311.     Begin
  312.       Val(st, number, code);
  313.       If code = 0 Then
  314.         num := number;
  315.     End;
  316.   End;                            {readreal}
  317.  
  318.  
  319.   Procedure greadstring(Var s : String; fieldwidth : Integer);
  320.  
  321.     { readlns a string from kbd in graphics mode}
  322.  
  323.   Var c          : Char;
  324.     colorinfo      : Word;
  325.  
  326.     Procedure backspace(c : Char);
  327.  
  328.       { backspaces cp over last char displayed (c)}
  329.  
  330.     Begin
  331.       moverel(-textwidth(c), 0);
  332.       setcolor(getpixel(getx+textwidth(' '), gety));
  333.                                     {assume empty character on }
  334.       outtext(c); {erase character} { right is background color}
  335.       moverel(-textwidth(c), 0);
  336.       setcolor(colorinfo);
  337.     End;                          {backspace}
  338.  
  339.   Begin                           {greadstring}
  340.     colorinfo := getcolor;
  341.     s := '';
  342.     Repeat
  343.       outtext('_');               {provide cursor}
  344.       c := readkey;
  345.       backspace('_');
  346.       Case c Of
  347.         ' '..'~' : If Length(s) < fieldwidth Then
  348.                    Begin
  349.                      s := s+c;
  350.                      outtext(s[Length(s)]);
  351.                    End;
  352.         #8, #$7f : If Length(s) > 0 Then {back space, del}
  353.                    Begin
  354.                      backspace(s[Length(s)]);
  355.                      Delete(s, Length(s), 1);
  356.                    End;
  357.       End;                        {case}
  358.     Until c = #13;
  359.   End;                            {greadstring}
  360.  
  361.  
  362.   Procedure greadinteger(Var num : Integer);
  363.  
  364. { readlns an integer from kbd in graphics mode. if enter or invalid entry is
  365.   entered, leaves num unchanged}
  366.  
  367.   Var st         : String;
  368.     code           : Integer;
  369.     number         : LongInt;
  370.  
  371.   Begin
  372.     greadstring(st, 6);
  373.     If st <> '' Then
  374.     Begin
  375.       Val(st, number, code);
  376.       If (code = 0) And (number >= -MaxInt) And (number <= MaxInt) Then
  377.         num := number;
  378.     End;
  379.   End;                            {greadinteger}
  380.  
  381.  
  382.   Procedure greadlongint(Var num : LongInt);
  383.  
  384. { readlns a long integer from kbd in graphics mode. if enter or invalid entry
  385.   is entered, leaves num unchanged}
  386.  
  387.   Var st         : String;
  388.     code           : Integer;
  389.     number         : LongInt;
  390.  
  391.   Begin
  392.     greadstring(st, 11);
  393.     If st <> '' Then
  394.     Begin
  395.       Val(st, number, code);
  396.       If code = 0 Then
  397.         num := number;
  398.     End;
  399.   End;                            {greadlongint}
  400.  
  401.  
  402.   Procedure greadreal(Var num : Real);
  403.  
  404. { readlns a real from kbd in graphics mode. if enter or invalid entry is
  405.   entered, leaves num unchanged}
  406.  
  407.   Var st         : String;
  408.     code           : Integer;
  409.     number         : Real;
  410.  
  411.   Begin
  412.     greadstring(st, 20);
  413.     If st <> '' Then
  414.     Begin
  415.       Val(st, number, code);
  416.       If code = 0 Then
  417.         num := number;
  418.     End;
  419.   End;                            {greadreal}
  420.  
  421.  
  422.   Procedure swapscreen;
  423.  
  424.     { change virtual graphics pages, saving current page to heap}
  425.  
  426.   Begin
  427.     If firstget[currentscreen] Then
  428.     Begin
  429.       GetMem(scrnbufp[currentscreen], imagesize(0, 0, getmaxx, getmaxy));
  430.       firstget[currentscreen] := False;
  431.     End;
  432.     getimage(0, 0, getmaxx, getmaxy, scrnbufp[currentscreen]^);
  433.     currentscreen := currentscreen Mod 2+1;
  434.     If firstput[currentscreen] Then
  435.     Begin
  436.       firstput[currentscreen] := False;
  437.       cleardevice;
  438.     End
  439.     Else
  440.       putimage(0, 0, scrnbufp[currentscreen]^, normalput);
  441.   End;                            {swapscreen}
  442.  
  443.  
  444.   Procedure leavegraph;
  445.  
  446.     { return to text mode, but save screen on heap}
  447.  
  448.   Begin
  449.     GetMem(scrnbufp[currentscreen], imagesize(0, 0, getmaxx, getmaxy));
  450.     getimage(0, 0, getmaxx, getmaxy, scrnbufp[currentscreen]^);
  451.     restorecrtmode;
  452.   End;                            {leavegraph}
  453.  
  454.  
  455.   Procedure entergraph(graphmode : Integer);
  456.  
  457.     { return to graphics mode, restoring saved screen from heap}
  458.  
  459.   Begin
  460.     setgraphmode(graphmode);
  461.     putimage(0, 0, scrnbufp[currentscreen]^, normalput);
  462.     FreeMem(scrnbufp[currentscreen], imagesize(0, 0, getmaxx, getmaxy));
  463.   End;                            {entergraph}
  464.  
  465.  
  466.   Procedure screendump;
  467.  
  468.     { graphics hardware independant graphics screen dump}
  469.  
  470.   Var column, row, total, bit, value : Integer;
  471.  
  472.   Begin
  473.     For row := 0 To (getmaxy Div 8)+1 Do
  474.     Begin
  475.       Write(lst, ^[ , 'A', #8);
  476.       Write(lst, ^[ , 'L', Chr(Succ(getmaxx) Mod 256),
  477.             Chr(Succ(getmaxx) Div 256));
  478.       For column := 0 To getmaxx Do
  479.       Begin
  480.         total := 0;
  481.         value := 128;
  482.         For bit := 0 To 7 Do
  483.         Begin
  484.           If getpixel(column, row*8+bit) <> black Then
  485.             total := total+value;
  486.           value := value Div 2;
  487.         End;
  488.         Write(lst, Chr(total));
  489.       End;
  490.       Write(lst, #13, #10);
  491.     End;
  492.   End;                            {screendump}
  493.  
  494.  
  495.   Procedure beep;
  496.  
  497.     { short beep on console }
  498.  
  499.   Begin
  500.     sound(1200);
  501.     delay(5);
  502.     nosound;
  503.   End;                            {beep}
  504.  
  505.  
  506.   Procedure selectcolor(color : Word);
  507.  
  508.     { calls setcolor with modified color value depending on available colors}
  509.  
  510.   Begin
  511.     If (getmaxcolor > 1) Or (color = black) Then
  512.       setcolor(color)
  513.     Else
  514.       setcolor(getmaxcolor);
  515.   End;                            {selectcolor}
  516.  
  517.  
  518.   Procedure selectbcolor(color : Word);
  519.  
  520.     { calls setcolor with modified background color value depending
  521.       on available colors}
  522.  
  523.   Begin
  524.     If getmaxcolor > 1 Then
  525.       setcolor(color)
  526.     Else
  527.       setcolor(black);
  528.   End;                            {selectcolor}
  529.  
  530.  
  531.   Procedure selectfillstyle(pattern : Word; color : Word);
  532.  
  533. { calls selectfillstyle with modified color value depending on available
  534.   colors}
  535.  
  536.   Begin
  537.     If (getmaxcolor > 1) Or (color = black) Then
  538.       setfillstyle(pattern, color)
  539.     Else
  540.       setfillstyle(pattern, getmaxcolor);
  541.   End;                            {selectfillstyle}
  542.  
  543.  
  544.   Procedure selectbfillstyle(pattern : Word; color : Word);
  545.  
  546. { calls selectfillstyle with modified background color value depending
  547.   on available colors}
  548.  
  549.   Begin
  550.     If getmaxcolor > 1 Then
  551.       setfillstyle(pattern, color)
  552.     Else
  553.       setfillstyle(pattern, black);
  554.   End;                            {selectfillstyle}
  555.  
  556.  
  557.   Procedure add_dialogentry(Var dp, lastdialogentry,
  558.                             dialogentryhead : dialogentryp);
  559.  
  560.     { appends dialog entry to list}
  561.  
  562.   Begin                           {add_dialogentry}
  563.     dp^.next := Nil;
  564.     If dialogentryhead = Nil Then
  565.       dialogentryhead := dp
  566.     Else
  567.       lastdialogentry^.next := dp;
  568.     lastdialogentry := dp;
  569.   End;                            {add_dialogentry}
  570.  
  571.  
  572.   Procedure dialog_box(dialog : dialogentryp; bcolor, color : Integer;
  573.                        continueprompt : Boolean);
  574.  
  575. { draws arguments messages in dialog box, allows editing of fields,
  576.   restores area under box}
  577.  
  578.   Const booleanfieldlength = 6;
  579.     charfieldlength = 1;
  580.     integerfieldlength = 6;
  581.     realfieldlength = 20;
  582.  
  583.   Var i, leftedge, rightedge, yposition, maxstringlength, narguments,
  584.     boxwidth, boxheight : Integer;
  585.     dp             : dialogentryp;
  586.     savep          : Pointer;
  587.     str1           : String;
  588.     c, cl          : Char;
  589.  
  590.  
  591.     Function leftargument(dp : dialogentryp) : Integer;
  592.  
  593.       {  calculates where left edge of argument field is for given argument
  594.          type}
  595.  
  596.  
  597.     Begin                         {leftargument}
  598.       Case dp^.argtype Of
  599.         _boolean : leftargument := rightedge-
  600.                    textwidth(Copy(bigemptystring, 1,
  601.                                   booleanfieldlength+1));
  602.         _char : leftargument := rightedge-
  603.                 textwidth(Copy(bigemptystring, 1,
  604.                                charfieldlength+1));
  605.         _integer : leftargument := rightedge-
  606.                    textwidth(Copy(bigemptystring, 1,
  607.                                   integerfieldlength+1));
  608.         _real : leftargument := rightedge-
  609.                 textwidth(Copy(bigemptystring, 1,
  610.                                realfieldlength+1));
  611.         _string : leftargument := rightedge-
  612.                   textwidth(Copy(bigemptystring, 1, dp^.ssize+1));
  613.       End;                        {case}
  614.     End;                          {leftargument}
  615.  
  616.  
  617.     Function valid_selection : Integer;
  618.  
  619.       { determines whether mouse arrow is over a valid field}
  620.  
  621.     Var valid      : Boolean;
  622.       dp             : dialogentryp;
  623.       lineno, i, bottomargument : Integer;
  624.  
  625.     Begin                         {valid_selection}
  626.       valid := False;
  627.       dp := dialog;
  628.       If (mousey > (getmaxy-boxheight) Div 2) And
  629.       (mousey < (getmaxy+boxheight) Div 2) Then
  630.       Begin
  631.         lineno := (mousey-(getmaxy-boxheight) Div 2+textheight(' '))
  632.         Div (textheight(' ')*2);
  633.         bottomargument := (getmaxy-boxheight) Div 2
  634.                           +textheight(' ')*(2*narguments+1);
  635.         If Not(lineno In [1..narguments]) Then
  636.           valid := (lineno = narguments+2) And continueprompt And
  637.           (mousex > leftedge+textwidth('  ')) And
  638.           (mousex < leftedge+textwidth('   Continue '))
  639.         Else
  640.         Begin
  641.           dp := dialog;           {find relevant dialog entry}
  642.           For i := 2 To lineno Do
  643.             dp := dp^.next;
  644.           Case dp^.argtype Of
  645.             _boolean : valid := (mousex > leftargument(dp)) And
  646.                        (mousex < leftargument(dp)+textwidth('      '));
  647.             _char, _integer, _real, _string : valid :=
  648.                                               (mousex > leftargument(dp)) And
  649.                                               (mousex < rightedge);
  650.           End;                    {case}
  651.         End;
  652.       End;
  653.       If valid Then
  654.         valid_selection := lineno
  655.       Else
  656.         valid_selection := -1;
  657.     End;                          {valid_selection}
  658.  
  659.  
  660.     Procedure display_argument(dp : dialogentryp);
  661.  
  662.       { displays dialog argument right justified}
  663.  
  664.     Var str1       : String;
  665.  
  666.     Begin                         {display_argument}
  667.       Case dp^.argtype Of
  668.         _boolean : Begin
  669.                      If dp^.booleanresult Then
  670.                        str1 := ' Y  n'
  671.                      Else
  672.                        str1 := ' y  N';
  673.                      outtextxy(leftargument(dp), yposition, str1);
  674.                      rectangle(leftargument(dp), yposition-textheight(' ')+1,
  675.                                leftargument(dp)+textwidth('   '),
  676.                                yposition+textheight(' '));
  677.                      rectangle(leftargument(dp)+textwidth('   '),
  678.                                yposition-textheight(' ')+1,
  679.                                leftargument(dp)+textwidth('      '),
  680.                                yposition+textheight(' '));
  681.                    End;
  682.         _char : outtextxy(leftargument(dp), yposition,
  683.                           Copy(bigemptystring, 1,
  684.                                charfieldlength-Length(dp^.charresult))
  685.                           +dp^.charresult);
  686.         _integer : Begin
  687.                      Str(dp^.integerresult, str1);
  688.                      outtextxy(leftargument(dp), yposition,
  689.                                Copy(bigemptystring, 1,
  690.                                     integerfieldlength-Length(str1))
  691.                                +str1);
  692.                    End;
  693.         _real : Begin
  694.                   Str(dp^.realresult:0:dp^.decimalp, str1);
  695.                   outtextxy(leftargument(dp), yposition,
  696.                             Copy(bigemptystring, 1,
  697.                                  realfieldlength-Length(str1))
  698.                             +str1);
  699.                 End;
  700.         _string : outtextxy(leftargument(dp), yposition,
  701.                             Copy(bigemptystring, 1,
  702.                                  dp^.ssize-Length(dp^.stringresult))
  703.                             +dp^.stringresult);
  704.       End;                        {case}
  705.     End;                          {display_argument}
  706.  
  707.  
  708.     Procedure clear_argument(dp : dialogentryp);
  709.  
  710.       { erases argument box for dp}
  711.  
  712.     Begin                         {clear_argument}
  713.       Case dp^.argtype Of
  714.         _boolean : bar(leftargument(dp), yposition-textheight(' ')+2,
  715.                        leftargument(dp)
  716.                        +textwidth(Copy(bigemptystring, 1, booleanfieldlength)),
  717.                        yposition+textheight(' ')-1);
  718.         _integer : bar(leftargument(dp), yposition-textheight(' ')+2,
  719.                        leftargument(dp)
  720.                        +textwidth(Copy(bigemptystring, 1, integerfieldlength)),
  721.                        yposition+textheight(' ')-1);
  722.         _char : bar(leftargument(dp), yposition-textheight(' ')+2,
  723.                     leftargument(dp)
  724.                     +textwidth(Copy(bigemptystring, 1, charfieldlength)),
  725.                     yposition+textheight(' ')-1);
  726.         _real : bar(leftargument(dp), yposition-textheight(' ')+2,
  727.                     leftargument(dp)
  728.                     +textwidth(Copy(bigemptystring, 1, realfieldlength)),
  729.                     yposition+textheight(' ')-1);
  730.         _string : bar(leftargument(dp), yposition-textheight(' ')+2,
  731.                       leftargument(dp)
  732.                       +textwidth(Copy(bigemptystring, 1, dp^.ssize)),
  733.                       yposition+textheight(' ')-1);
  734.       End;                        {case}
  735.     End;                          {clear_argument}
  736.  
  737.  
  738.     Procedure underline(dp : dialogentryp; show : Boolean);
  739.  
  740. { places underline below argument field ready for user input. show indicates
  741.   whether line should be drawn or erased}
  742.  
  743.     Begin                         {underline}
  744.       If show Then
  745.         selectcolor(color)
  746.       Else
  747.         selectbcolor(bcolor);
  748.       Case dp^.argtype Of
  749.         _integer : line(leftargument(dp), yposition+textheight(' '),
  750.                         leftargument(dp)+
  751.                         textwidth(Copy(bigemptystring, 1, integerfieldlength)),
  752.                         yposition+textheight(' '));
  753.         _char : line(leftargument(dp), yposition+textheight(' '),
  754.                      leftargument(dp)
  755.                      +textwidth(Copy(bigemptystring, 1, charfieldlength)),
  756.                      yposition+textheight(' '));
  757.         _real : line(leftargument(dp), yposition+textheight(' '),
  758.                      leftargument(dp)
  759.                      +textwidth(Copy(bigemptystring, 1, realfieldlength)),
  760.                      yposition+textheight(' '));
  761.         _string : line(leftargument(dp), yposition+textheight(' '),
  762.                        leftargument(dp)
  763.                        +textwidth(Copy(bigemptystring, 1, dp^.ssize)),
  764.                        yposition+textheight(' '));
  765.       End;                        {case}
  766.       selectcolor(color);
  767.     End;                          {underline}
  768.  
  769.  
  770.   Begin                           {dialog_box}
  771.     mousearrowoff;
  772.     settextjustify(lefttext, centertext);
  773.     selectcolor(color);
  774.     selectbfillstyle(solidfill, bcolor);
  775.     maxstringlength := 0;
  776.     dp := dialog;
  777.     narguments := 0;
  778.     While dp <> Nil Do            {find longest line}
  779.     Begin
  780.       Inc(narguments);
  781.       Case dp^.argtype Of
  782.         _none : i := 0;
  783.         _boolean : i := booleanfieldlength+2;
  784.         _char : i := charfieldlength+2;
  785.         _integer : i := integerfieldlength+2;
  786.         _real : i := realfieldlength+2;
  787.         _string : i := dp^.ssize+2;
  788.       End;                        {case}
  789.       If i+Length(dp^.title) > maxstringlength Then
  790.         maxstringlength := i+Length(dp^.title);
  791.       dp := dp^.next;
  792.     End;
  793.     boxwidth := textwidth(Copy(bigemptystring, 1, maxstringlength+2));
  794.     boxheight := (narguments*2+2+4*Ord(continueprompt))*textheight(' ');
  795.     leftedge := (getmaxx-boxwidth) Div 2+textwidth(' ');
  796.     rightedge := (getmaxx+boxwidth) Div 2-textwidth(' ');
  797.     GetMem(savep,
  798.            imagesize((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  799.                      (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2));
  800.     getimage((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  801.              (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2,
  802.              savep^);             {save image}
  803.     bar((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  804.         (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2);
  805.     rectangle((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  806.               (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2);
  807.     dp := dialog;
  808.     For i := 1 To narguments+Ord(continueprompt) Do
  809.     Begin
  810.       yposition := (getmaxy-boxheight) Div 2+textheight(' ')*i*2;
  811.       If i > narguments Then
  812.       Begin
  813.         outtextxy(leftedge, yposition+textheight(' ')*2,
  814.                   '   Continue');
  815.         rectangle(leftedge+textwidth('  '), yposition+textheight(' '),
  816.                   leftedge+textwidth('   Continue '),
  817.                   yposition+textheight(' ')*3);
  818.       End
  819.       Else
  820.       Begin
  821.         outtextxy(leftedge, yposition, dp^.title);
  822.         display_argument(dp);
  823.       End;
  824.       dp := dp^.next;
  825.     End;
  826.     Repeat
  827.       i := 1;
  828.       If (narguments > 1) Or (dialog^.argtype = _boolean)
  829.         Or continueprompt Then
  830.       Begin
  831.         mousearrowon;
  832.         Repeat
  833.           Repeat
  834.             c := trackmouse;
  835.           Until (mousekeys > 0) Or (c In [^c, ^m]);
  836.           If mousekeys = 1 Then
  837.             i := valid_selection
  838.           Else
  839.             i := 0;
  840.         Until (c In [^c, ^m]) Or (i > -1);
  841.         mousearrowoff;
  842.       End;
  843.       If (i In [1..narguments]) And (c <> ^c) And Not((c = ^m)
  844.            And (narguments > 1)) Then
  845.       Begin
  846.         yposition := (getmaxy-boxheight) Div 2+textheight(' ')*i*2;
  847.         dp := dialog;
  848.         For i := 2 To i Do
  849.           dp := dp^.next;
  850.         Case dp^.argtype Of
  851.           _boolean : Begin
  852.                        dp^.booleanresult := (c = ^m) Or
  853.                        (mousex < leftargument(dp)+textwidth('   '));
  854.                        clear_argument(dp);
  855.                        display_argument(dp);
  856.                      End;
  857.           _integer, _real, _string :
  858.             Begin
  859.               Repeat Until keypressed Or (narguments > 1) Or (mousekeys > 1);
  860.               If mousekeys < 2 Then
  861.               Begin
  862.                 clear_argument(dp);
  863.                 underline(dp, True);
  864.                 moveto(leftargument(dp), yposition);
  865.                 Case dp^.argtype Of
  866.                   _integer : greadinteger(dp^.integerresult);
  867.                   _real : greadreal(dp^.realresult);
  868.                   _string : Begin
  869.                               str1 := dp^.stringresult;
  870.                               greadstring(dp^.stringresult, dp^.ssize);
  871.                               If Not dp^.nulvalid And
  872.                               (Length(dp^.stringresult) = 0) Then
  873.                                 dp^.stringresult := str1;
  874.                             End;
  875.                 End;              {case}
  876.                 underline(dp, False);
  877.                 clear_argument(dp);
  878.                 display_argument(dp);
  879.               End;
  880.             End;
  881.           _char : Begin
  882.                     Repeat
  883.                     Until keypressed Or (narguments > 1) Or (mousekeys > 1);
  884.                     If mousekeys < 2 Then
  885.                     Begin
  886.                       clear_argument(dp);
  887.                       underline(dp, True);
  888.                       cl := readkey;
  889.                       If cl <> ^m Then
  890.                       Begin
  891.                         outtextxy(leftargument(dp), yposition, cl);
  892.                         dp^.charresult := cl;
  893.                       End;
  894.                       underline(dp, False);
  895.                     End;
  896.                   End;
  897.         End;                      {case}
  898.       End;
  899.  
  900.     Until ((narguments = 1) And Not(continueprompt)) Or (i > narguments)
  901.     Or (continueprompt And (c = ^m)) Or (i = 0);
  902.     putimage((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2, savep^,
  903.              normalput);
  904.     FreeMem(savep,
  905.             imagesize((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  906.                       (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2));
  907.     mousearrowon;
  908.   End;                            {dialog_box}
  909.  
  910.  
  911.   Procedure dispose_dialog(Var dp : dialogentryp);
  912.  
  913.     { disposes of all entries in dialog list}
  914.  
  915.   Var d          : dialogentryp;
  916.  
  917.   Begin                           {dispose_dialog}
  918.     d := dp;
  919.     While d <> Nil Do
  920.     Begin
  921.       d := d^.next;
  922.       Dispose(dp);
  923.       dp := d;
  924.     End;
  925.   End;                            {dispose_dialog}
  926.  
  927.  
  928.   Procedure fill_background(color, fillpattern, arcsize : Word);
  929.  
  930.     { fills background with color and rounds the corners}
  931.  
  932.   Var xasp, yasp : Word;
  933.     aspect         : Real;
  934.  
  935.   Begin
  936.     cleardevice;
  937.     selectcolor(color);
  938.     getaspectratio(xasp, yasp);
  939.     aspect := 1.0*xasp/yasp;
  940.     selectfillstyle(fillpattern, color);
  941.     setlinestyle(userbitln, 0, normwidth); {no outline}
  942.     bar(0, 0, getmaxx, getmaxy);
  943.  
  944.     selectfillstyle(solidfill, black);
  945.     bar(0, 0, Pred(arcsize), Pred(Round(arcsize*aspect)));
  946.     selectfillstyle(fillpattern, color);
  947.     pieslice(arcsize, Round(arcsize*aspect), 90, 180, arcsize);
  948.  
  949.     selectfillstyle(solidfill, black);
  950.     bar(Succ(getmaxx-arcsize), 0, getmaxx, Pred(Round(arcsize*aspect)));
  951.     selectfillstyle(fillpattern, color);
  952.     pieslice(getmaxx-arcsize, Round(arcsize*aspect), 0, 90, arcsize);
  953.  
  954.     selectfillstyle(solidfill, black);
  955.     bar(0, getmaxy, Pred(arcsize), Succ(getmaxy-Round(arcsize*aspect)));
  956.     selectfillstyle(fillpattern, color);
  957.     pieslice(arcsize, getmaxy-Round(arcsize*aspect), 180, 270, arcsize);
  958.  
  959.     selectfillstyle(solidfill, black);
  960.     bar(Succ(getmaxx-arcsize), getmaxy, getmaxx,
  961.         Succ(getmaxy-Round(arcsize*aspect)));
  962.     selectfillstyle(fillpattern, color);
  963.     pieslice(getmaxx-arcsize, getmaxy-Round(arcsize*aspect), 270,
  964.              360, arcsize);
  965.     selectcolor(black);
  966.     setlinestyle(solidln, 0, normwidth);
  967.   End;                            {fill_background}
  968.  
  969.  
  970.   Procedure panel(x, y : Integer; width, height, color : Word);
  971.  
  972.     { draws solid panel with center top at x,y, width by height}
  973.  
  974.   Var currentcolor : Word;
  975.  
  976.   Begin
  977.     currentcolor := getcolor;
  978.     selectcolor(color);
  979.     selectfillstyle(solidfill, color);
  980.     bar(x-width Div 2, y, x+width Div 2, y+height);
  981.     selectcolor(currentcolor);
  982.   End;                            {panel}
  983.  
  984.  
  985.   Procedure add_clickboxentry(Var cp, lastclickbox,
  986.                               clickboxhead : clickboxtypep);
  987.  
  988.     { appends clickbox to list}
  989.  
  990.   Begin                           {add_clickboxentry}
  991.     cp^.next := Nil;
  992.     If clickboxhead = Nil Then
  993.       clickboxhead := cp
  994.     Else
  995.       lastclickbox^.next := cp;
  996.     lastclickbox := cp;
  997.   End;                            {add_clickboxentry}
  998.  
  999.  
  1000.   Function box_width(cp : clickboxtypep) : Integer;
  1001.  
  1002.     { calculates width of click box}
  1003.  
  1004.   Var i, boxwidth : Integer;
  1005.     p              : polypointp;
  1006.     pi             : LongInt Absolute p;
  1007.  
  1008.   Begin                           {boxwidth}
  1009.     Case cp^.ttype Of
  1010.       _text : box_width := textwidth(cp^.title+'  ');
  1011.       _figure : Begin
  1012.                   boxwidth := 0;
  1013.                   p := cp^.polypoints;
  1014.                   For i := 1 To cp^.numpoints Do
  1015.                   Begin
  1016.                     If p^.x > boxwidth Then
  1017.                       boxwidth := p^.x;
  1018.                     pi := pi+4;
  1019.                   End;
  1020.                   box_width := textwidth(' ')
  1021.                                *(Succ(boxwidth) Div textwidth(' ')+2);
  1022.                 End;
  1023.     End;                          {case}
  1024.   End;                            {box_width}
  1025.  
  1026.  
  1027.   Procedure draw_clicklist(cp : clickboxtypep; x, y, bcolor, color : Integer);
  1028.  
  1029.     { draws list of click boxes}
  1030.  
  1031.  
  1032.     Procedure draw_clickbox(cp : clickboxtypep; x, y : Integer);
  1033.  
  1034.       { draws one click box}
  1035.  
  1036.     Var boxwidth, boxheight : Integer;
  1037.       viewport       : viewporttype;
  1038.  
  1039.     Begin                         {draw_clickbox}
  1040.       settextjustify(lefttext, centertext);
  1041.       boxwidth := box_width(cp);
  1042.       boxheight := textheight(' ')*2;
  1043.       selectbfillstyle(solidfill, bcolor);
  1044.       bar(x+cp^.x, y+cp^.y, x+cp^.x+boxwidth, y+cp^.y+boxheight);
  1045.       rectangle(x+cp^.x, y+cp^.y, x+cp^.x+boxwidth, y+cp^.y+boxheight);
  1046.       selectfillstyle(solidfill, color);
  1047.       Case cp^.ttype Of
  1048.         _text : outtextxy(x+cp^.x, y+cp^.y+textheight(' '), ' '+cp^.title);
  1049.         _figure : Begin
  1050.                     getviewsettings(viewport);
  1051.                     setviewport(cp^.x+x+textwidth(' '), cp^.y+y,
  1052.                                 cp^.x+x+boxwidth, cp^.y+y+boxheight, True);
  1053.                     drawpoly(cp^.numpoints, cp^.polypoints^);
  1054.                     If cp^.fill Then
  1055.                       fillpoly(cp^.numpoints, cp^.polypoints^);
  1056.                     setviewport(viewport.x1, viewport.y1,
  1057.                                 viewport.x2, viewport.y2, viewport.clip);
  1058.                   End;
  1059.       End;                        {case}
  1060.     End;                          {draw_clickbox}
  1061.  
  1062.  
  1063.   Begin                           {draw_clicklist}
  1064.     selectcolor(color);
  1065.     While cp <> Nil Do
  1066.     Begin
  1067.       draw_clickbox(cp, x, y);
  1068.       cp := cp^.next;
  1069.     End;
  1070.   End;                            {draw_clicklist}
  1071.  
  1072.  
  1073.   Function click_selection(cp : clickboxtypep; x, y : Integer) : Integer;
  1074.  
  1075.     { tests whether mouse is over a click box and returns its number in
  1076.       the list}
  1077.  
  1078.   Var boxno      : Integer;
  1079.     found          : Boolean;
  1080.  
  1081.   Begin                           {click_selection}
  1082.     found := False;
  1083.     boxno := 0;
  1084.     While Not found And (cp <> Nil) Do
  1085.     Begin
  1086.       found := (mousex >= x+cp^.x) And (mousex <= x+cp^.x+box_width(cp)) And
  1087.         (mousey >= y+cp^.y) And (mousey <= cp^.y+y+textheight(' ')*2);
  1088.       Inc(boxno);
  1089.       If Not found Then
  1090.         cp := cp^.next;
  1091.     End;
  1092.     If cp <> Nil Then
  1093.       click_selection := boxno
  1094.     Else
  1095.       click_selection := -1;
  1096.   End;                            {click_selection}
  1097.  
  1098.  
  1099.   Procedure dispose_clickboxlist(Var cp : clickboxtypep);
  1100.  
  1101.     { disposes of all entries in click box list}
  1102.  
  1103.   Var c          : clickboxtypep;
  1104.  
  1105.   Begin                           {dispose_clickboxlist}
  1106.     c := cp;
  1107.     While c <> Nil Do
  1108.     Begin
  1109.       c := c^.next;
  1110.       Dispose(cp);
  1111.       cp := c;
  1112.     End;
  1113.   End;                            {dispose_clickboxlist}
  1114.  
  1115.  
  1116.   Procedure display_message(s : String; bcolor, color : Integer;
  1117.                             Var storagep : Pointer;
  1118.                             show           : Boolean);
  1119.  
  1120. { draws message in box at screen center (or restores screen if show=false).
  1121.  a storage pointer must be supplied to allow reentrance}
  1122.  
  1123.   Var boxwidth, boxheight : Integer;
  1124.  
  1125.   Begin                           {display_message}
  1126.     settextjustify(lefttext, centertext);
  1127.     boxwidth := textwidth(s+'  ');
  1128.     boxheight := textheight(' ')*2;
  1129.     If show Then
  1130.     Begin
  1131.       selectcolor(color);
  1132.       selectbfillstyle(solidfill, bcolor);
  1133.       GetMem(storagep,
  1134.              imagesize((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  1135.                        (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2));
  1136.       getimage((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  1137.                (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2, storagep^);
  1138.       bar((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  1139.           (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2);
  1140.       rectangle((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  1141.                 (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2);
  1142.       outtextxy((getmaxx-boxwidth) Div 2, getmaxy Div 2, ' '+s);
  1143.     End
  1144.     Else
  1145.     Begin
  1146.       putimage((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2, storagep^,
  1147.                normalput);
  1148.       FreeMem(storagep,
  1149.               imagesize((getmaxx-boxwidth) Div 2, (getmaxy-boxheight) Div 2,
  1150.                         (getmaxx+boxwidth) Div 2, (getmaxy+boxheight) Div 2));
  1151.     End;
  1152.   End;                            {display_message}
  1153.  
  1154.  
  1155.   Function continue_prompt(x, y, bcolor, color : Integer) : Char;
  1156.  
  1157.     { displays continue prompt and waits for button or key}
  1158.  
  1159.   Var cp         : clickboxtypep;
  1160.     c              : Char;
  1161.     j              : Integer;
  1162.  
  1163.   Begin                           {continue_prompt}
  1164.     c := '.';
  1165.     settextstyle(defaultfont, horizdir, 1);
  1166.     New(cp);
  1167.     With cp^ Do
  1168.     Begin
  1169.       ttype := _text;
  1170.       title := 'Continue';
  1171.       x := 0;
  1172.       y := 0;
  1173.       next := Nil;
  1174.     End;
  1175.     If x < 0 Then
  1176.       x := getmaxx+x-textwidth(cp^.title+'  ');
  1177.     If y < 0 Then
  1178.       y := getmaxy+y-textheight(' ')*2;
  1179.     draw_clicklist(cp, x, y, bcolor, color);
  1180.     j := -1;
  1181.     mousearrowon;
  1182.     Repeat
  1183.       Repeat
  1184.         c := trackmouse;
  1185.       Until (mousekeys > 0) Or (c In [^c, ^m]);
  1186.       If mousekeys > 1 Then
  1187.         j := 0
  1188.       Else
  1189.         If mousekeys = 1 Then
  1190.           j := click_selection(cp, x, y);
  1191.     Until (j > -1) Or (c In [^c, ^m]);
  1192.     dispose_clickboxlist(cp);
  1193.     continue_prompt := c;
  1194.   End;                            {continue_prompt}
  1195.  
  1196.  
  1197. Begin                             {initialisation}
  1198.   exitsave := ExitProc;           {install myerror}
  1199.   ExitProc := @myexit;
  1200.   showerrormessage := True;
  1201.   For i := 1 To screens Do
  1202.   Begin
  1203.     firstget[i] := True;
  1204.     firstput[i] := True;
  1205.   End;
  1206.   currentscreen := 1;
  1207. End.
  1208.